/**
 * @author Tobias Boehm
 *
 * 28.04.2011
 */
package org.anddev.andengine.extension.tbsengine.map;

import java.io.IOException;

import org.anddev.andengine.engine.Engine;
import org.anddev.andengine.entity.layer.tiled.tmx.TMXLoader;
import org.anddev.andengine.entity.layer.tiled.tmx.TMXTiledMap;
import org.anddev.andengine.entity.layer.tiled.tmx.util.exception.TMXLoadException;
import org.anddev.andengine.opengl.buffer.BufferObjectManager;

import android.content.Context;

/**
 * This is an abstract implementation of a map loader. It provides you with 
 * methods to load a map by providing an instance of your implementation of
 * {@link AbsMapOverview} which is related to the wanted map.
 * <p>
 * Notice:<br>
 * There are two methods for loading a map.<br>
 * {@link #loadClientMap(AbsMapOverview)} should be used to load a map object on
 * the client side. It will also load all necessary tile texture into the memory.
 * <br>
 * {@link #loadServerMap(AbsMapOverview)} should be used on the server side. It 
 * will load a more lightweight map and does not load the tile textures.
 * 
 * @author Tobias Boehm
 *
 * @param <MapOverviewClass> - Your implementation of {@link AbsMapOverview}.
 * @param <MapClass> - Your implementation of {@link AbsMap}.
 */
public abstract class AbsMapLoader<MapOverviewClass extends AbsMapOverview, MapClass extends AbsMap> extends FilePathsResolver {

	/**
	 * A reference to the game engine.
	 */
	private final Engine mEngine;
	
	private final Context mContext;
	
	
	/**
	 * This is the default constructor. You should use it if you do not 
	 * implement a costume map file suffix.
	 * 
	 * @param pContext
	 * @param pEngine - A reference to the game engine.
	 * @param pMapFolderPath - The path to the map folder.
	 * 
	 * @throws IOException if there is a problem by reading the file list of the given folder path
	 */
	public AbsMapLoader(final Context pContext, final Engine pEngine, final String pMapFolderPath) throws IOException{
		
		this(pContext, pEngine, pMapFolderPath, STANDARD_MAP_FILE_SUFFIX);
	}
	
	/**
	 * This is an advanced constructor. You can provide your own map file suffix
	 * as a parameter.
	 * 
	 * @param pContext
	 * @param pEngine - A reference to the game engine.
	 * @param pMapFolderPath - The path to the map folder.
	 * @param pMapFilesSuffix - Your costume map file suffix. Example: <code>"map"</code>
	 * 
	 * @throws IOException if there is a problem by reading the file list of the given folder path
	 */
	public AbsMapLoader(final Context pContext, final Engine pEngine, final String pMapFolderPath, final String pMapFilesSuffix) throws IOException{
		
		super(pContext, pMapFolderPath, pMapFilesSuffix);
		
		this.mContext = pContext;
		
		this.mEngine = pEngine;
	}
	
	/**
	 * This method loads and returns an instance of your implementation of 
	 * {@link AbsMap}. It also loads all tile textures into the memory which is
	 * necessary for the client side of your game.
	 * 
	 * @param pMapOverview - The instance of your implementation of {@link AbsMapOverview} related to the wanted map.
	 * 
	 * @return an instance of your implementation of {@link AbsMap}.
	 * 
	 * @throws TMXLoadException if there is a problem with parsing the corresponding map file.
	 */
	public MapClass loadClientMap(final MapOverviewClass pMapOverview) throws TMXLoadException{
		
		final TMXLoader tmxLoader = new TMXLoader(this.mContext, this.mEngine.getTextureManager());
				
		final TMXTiledMap tmxMap = tmxLoader.loadFromAsset(this.mContext, pMapOverview.getMapFilePath());

		final MapClass tbsMap = this.createMap(tmxMap);
				
		return tbsMap;
	}
	
	/**
	 * This method loads and returns an instance of your implementation of 
	 * {@link AbsMap}. It does NOT load the tile textures into the memory. You
	 * should use this method only for your server side implementation.
	 * <p>
	 * Notice:<br>
	 * Right now the method initially loads the tile textures and then
	 * unloads them as soon as possible. This behavior will change in a later
	 * development stage. 
	 * 
	 * @param pMapOverview
	 * 
	 * @return
	 * 
	 * @throws TMXLoadException
	 */
	public MapClass loadServerMap(final MapOverviewClass pMapOverview) throws TMXLoadException{
		
		final TMXLoader tmxLoader = new TMXLoader(this.mContext, this.mEngine.getTextureManager());
				
		final TMXTiledMap tmxMap = tmxLoader.loadFromAsset(this.mContext, pMapOverview.getMapFilePath());

		// TODO: find a more efficient solution compared to loading and unloading the map tile textures
		BufferObjectManager.getActiveInstance().unloadBufferObject(tmxMap.getSharedVertexBuffer());
		
		final MapClass tbsMap = this.createMap(tmxMap);
		
		return tbsMap;
	}

	/**
	 * This method should return an instance of your implementation of {@link AbsMap}.
	 * 
	 * @param pTMXtiledMap - The {@link TMXTiledMap} loaded previously.
	 * 
	 * @return an instance of your implementation of {@link AbsMap}.
	 */
	protected abstract MapClass createMap(final TMXTiledMap pTMXtiledMap);
}
